package top.wuchu.rpc.transport.socket.util;

import top.wuchu.rpc.entity.RpcRequest;
import top.wuchu.rpc.enumeration.PackageType;
import top.wuchu.rpc.serializer.CommonSerializer;

import java.io.IOException;
import java.io.OutputStream;

/**
 *  将请求体内容写通过我们自定义的格式写到输出流中
 * @author WuChu
 */
public class ObjectWriter {

    // 自定义的网络传输包的数据格式
//            +---------------+---------------+-----------------+-------------+
//            |  Magic Number |  Package Type | Serializer Type | Data Length |
//            |    4 bytes    |    4 bytes    |     4 bytes     |   4 bytes   |
//            +---------------+---------------+-----------------+-------------+
//            |                          Data Bytes                           |
//            |                   Length: ${Data Length}                      |
//            +---------------------------------------------------------------+

    private static final int MAGIC_NUMBER = 0xCAFEBABE;

    public static void writeObject(OutputStream outputStream, Object object, CommonSerializer serializer) throws IOException {

        // 1、魔数，表识一个 MRF 协议包，0xCAFEBABE
        outputStream.write(intToBytes(MAGIC_NUMBER));

        // 2、Package Type	包类型，标明这是一个调用请求还是调用响应
        if (object instanceof RpcRequest) {
            outputStream.write(intToBytes(PackageType.REQUEST_PACK.getCode()));
        } else {
            outputStream.write(intToBytes(PackageType.RESPONSE_PACK.getCode()));
        }

        // 3、Serializer Type 序列化器类型，标明这个包的数据的序列化方式
        outputStream.write(intToBytes(serializer.getCode()));


        // ****通过用户选择的序列化协议对请求包进行序列化****
        byte[] bytes = serializer.serialize(object);

        // 4、Data Length	数据字节的长度
        outputStream.write(intToBytes(bytes.length));

        // 5、Data Bytes	传输的对象，通常是一个RpcRequest或RpcClient对象，取决于Package Type字段，
        // 对象的序列化方式取决于Serializer Type字段。
        outputStream.write(bytes);

        // 将缓冲区的数据发送到目的地，一般write()之后不flush的话是默认等缓冲区满了之后再将数据发送
        // 加了flush()是马上就将数据发送过去，不用等缓冲区存满
        outputStream.flush();

    }

    /**
     * 将一个int类型的值转化为字节
     * @param value
     * @return
     */
    private static byte[] intToBytes(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) ((value>>24) & 0xFF);
        src[1] = (byte) ((value>>16)& 0xFF);
        src[2] = (byte) ((value>>8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return src;
    }
}
